#
# Copyright 2010 Red Hat, Inc. and/or its affiliates.
#
# Licensed to you under the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.  See the files README and
# LICENSE_GPL_v2 which accompany this distribution.
#

"""
A module with tests to see if volume operations are working.
"""
import unittest as ut
import sys
import os

import basicVdsTest as vdst
import vdsClient as vdsc
from storageConnectionTestUtils import eStorageType, disconnectFromStorage, connectToStorage, validateConnections, limitTestToConnectionType, CONNECTIONS_OPTION_DEFAULT
from storageDomainTestUtils import eDomainClass, generateDomainTargets, destroyDomainTargets
from confUtils import Validate
from enum import Enum
from agentUtils import connectAgent
from testUtils import cleanVdsm

sys.path.append("../../")
from storage.sd import BLANK_UUID

eVolumeType = Enum(
    Leaf = 'LEAF',
    Shared = 'SHARED',
    Internal = 'INTERNAL'
)

__commonConfig__ = {
    "VdsUri1" : {"default" : "http://server:54321"},
    "Connections" : {"default" : CONNECTIONS_OPTION_DEFAULT, "validator" : validateConnections},
    "DomainClass1" : {"default" : "data", "validator" : eDomainClass.parse},
    "Domain1" : {"default" : "GUID, GUID", "validator" : Validate.list},
    "StorageType1": {"default" : "nfs", "validator" : eStorageType.parse},
    "HostID1" : {"default" : 7, "validator" : Validate.int},
    "Pool1Key" : {"default" : "NFSKEY"}
}

class VolumeTestCaseBase(vdst.BasicVDSTest):
    #For convenience. I didn't put it in the base class because I didn't want to commit.
    mycfg = property(lambda self: self.cfg[self.__class__.__name__])
    @classmethod
    def getConfigTemplate(cls):
        return {cls.__name__ : __commonConfig__}

    def setUp(self):
        #Setup client
        self.client = vdsc.VDSClient()
        self.client.setURI(self.mycfg["VdsUri1"])

        #Make sure env is clean
        resp = self.assertVdscOK(self.client.getConnectedStoragePoolsList())
        self.assertTrue(len(resp['poollist']) == 0, "VDSM is connected to a pool. Dirty env. Bailing out.")

        #Handle storage configuration
        connectToStorage(self.client, self.mycfg["Connections"])
        self.domainTarget1 = generateDomainTargets(self.client, self.mycfg["Connections"], [self.mycfg["Domain1"]])[0]

        #setup test variables
        self.sdUUID = self.client.newUUID()
        self.spUUID = self.client.newUUID()

        #Create the tmp domain
        self.assertVdscOK(
            self.client.createStorageDomain(self.mycfg["StorageType1"], self.sdUUID,
                "Storage Domain 1", self.domainTarget1, self.mycfg["DomainClass1"]
            )
        )

        #Create tmp pool
        self.assertVdscOK(
            self.client.createStoragePool(self.spUUID, "Swimming Pool", self.sdUUID, [self.sdUUID], 1)
            )

        self.assertVdscOK(
            self.client.connectStoragePool(self.spUUID, self.mycfg["HostID1"], self.mycfg["Pool1Key"])
            )

        taskid = self.assertVdscOK(self.client.spmStart(self.spUUID, -1, -1, -1, False))['uuid']
        self.assertVdscTaskOK(self.client, taskid)

        self.assertVdscOK(
            self.client.activateStorageDomain(self.sdUUID, self.spUUID)
        )

    def tearDown(self):
        cleanVdsm(self.client, self.mycfg["HostID1"], self.mycfg["Connections"])

class RefCountTest(VolumeTestCaseBase):
    def setUp(self):
        self.agent = connectAgent(self.mycfg["VdsUri1"])

        VolumeTestCaseBase.setUp(self)

        self.baseVolUUID = vdsc.VDSClient.newUUID()
        self.baseImgUUID = vdsc.VDSClient.newUUID()
        self.templateVolUUID = vdsc.VDSClient.newUUID()
        self.templateImgUUID = vdsc.VDSClient.newUUID()
        self.templateVmUUID = vdsc.VDSClient.newUUID()
        self.newVolUUID1 = vdsc.VDSClient.newUUID()
        self.newImgUUID1 = vdsc.VDSClient.newUUID()
        self.newVolUUID2 = vdsc.VDSClient.newUUID()
        self.newImgUUID2 = vdsc.VDSClient.newUUID()
        self.newVolUUID3 = vdsc.VDSClient.newUUID()
        self.newImgUUID3 = vdsc.VDSClient.newUUID()

        volsize = str(100 * (2 ** 20))

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.baseImgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.baseVolUUID, "Base volume")
        )

        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.baseImgUUID, self.baseVolUUID)
        )['path']

        taskID = self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, self.templateVmUUID, self.baseImgUUID,
                self.baseVolUUID, self.templateImgUUID, self.templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL, blocked = False)
        )['uuid']
        self.assertVdscTaskOK(self.client, taskID, 999)

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.newImgUUID1, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.newVolUUID1, "Base volume",
                self.templateImgUUID, self.templateVolUUID)
        )
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.newImgUUID2, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.newVolUUID2, "Base volume",
                self.templateImgUUID, self.templateVolUUID)
        )
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.newImgUUID3, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.newVolUUID3, "Base volume",
                self.templateImgUUID, self.templateVolUUID)
        )

    def test(self):
        volumes = [
            (self.sdUUID, self.templateVolUUID),
            (self.sdUUID, self.newVolUUID1),
            (self.sdUUID, self.newVolUUID2),
            (self.sdUUID, self.newVolUUID3)
        ]

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.newImgUUID1, self.newVolUUID1)
        )
        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.newImgUUID2, self.newVolUUID2)
        )
        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.newImgUUID3, self.newVolUUID3)
        )

        volumeAvailability = self.agent.checkVolumeAvailability(volumes)

        for entry in volumeAvailability:
            self.assertTrue(entry)

        self.assertVdscOK(
            self.client.teardownVolume(self.sdUUID, self.spUUID, self.newImgUUID1, self.newVolUUID1)
        )
        self.assertVdscOK(
            self.client.teardownVolume(self.sdUUID, self.spUUID, self.newImgUUID2, self.newVolUUID2)
        )
        self.assertVdscOK(
            self.client.teardownVolume(self.sdUUID, self.spUUID, self.newImgUUID3, self.newVolUUID3)
        )

        volumeAvailability = self.agent.checkVolumeAvailability(volumes)

        for entry in volumeAvailability:
            self.assertFalse(entry)

class NewVolumeInfo(VolumeTestCaseBase):
    def setUp(self):
        VolumeTestCaseBase.setUp(self)

        self.imgUUID = vdsc.VDSClient.newUUID()
        self.volUUID = vdsc.VDSClient.newUUID()

        volsize = 2048

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID, "Volly The Volume")
        )

    def test(self):

        info = self.assertVdscOK(
            self.client.getVolumeInfo(self.sdUUID, self.spUUID,
                self.imgUUID, self.volUUID))['info']

        self.assertTrue("capacity" in info)
        self.assertFalse("size" in info)


class SetVolumeDescription(VolumeTestCaseBase):
    def setUp(self):
        VolumeTestCaseBase.setUp(self)

        self.imgUUID = vdsc.VDSClient.newUUID()
        self.volUUID = vdsc.VDSClient.newUUID()

        volsize = 5120

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID, "Volly The Volume")
        )

    def test(self):
        newDescription = "And now for something completely different."
        self.assertVdscOK(
            self.client.setVolumeDescription(self.sdUUID, self.spUUID,
                self.imgUUID, self.volUUID, newDescription)
        )

        currentDescription = self.assertVdscOK(
            self.client.getVolumeInfo(self.sdUUID, self.spUUID,
                self.imgUUID, self.volUUID))['info']['description']

        self.assertEquals(currentDescription, newDescription)

class DeleteVolume(VolumeTestCaseBase):
    def setUp(self):
        VolumeTestCaseBase.setUp(self)

        self.imgUUID = vdsc.VDSClient.newUUID()
        self.volUUID = vdsc.VDSClient.newUUID()
        self.volUUID1 = vdsc.VDSClient.newUUID()
        self.templateVolUUID = vdsc.VDSClient.newUUID()
        self.templateImgUUID = vdsc.VDSClient.newUUID()
        self.templateVmUUID = vdsc.VDSClient.newUUID()

        volsize = 2048

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID, "Base volume")
        )

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Snapshot 1 volume",
                self.imgUUID, self.volUUID)
        )

    def deleteVol(self):
        self.assertVdscOK(
            self.client.deleteVolume(self.sdUUID, self.spUUID, self.imgUUID, [self.volUUID1], True, False)
        )

    def forcedDeleteVol(self):
        self.assertVdscOK(
            self.client.deleteVolume(self.sdUUID, self.spUUID, self.imgUUID, [self.volUUID1], True, True)
        )

    def deleteVolWithChildren(self):
        self.assertVdscFail(
            self.client.deleteVolume(self.sdUUID, self.spUUID, self.imgUUID, [self.volUUID], True, False)
        )

    def forcedDeleteVolWithChildren(self):
        self.assertVdscOK(
            self.client.deleteVolume(self.sdUUID, self.spUUID, self.imgUUID, [self.volUUID], True, True)
        )

    def deleteSharedVol(self):
        self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, self.templateVmUUID, self.imgUUID,
                self.volUUID1, self.templateImgUUID, self.templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL)
        )

        self.assertVdscFail(
            self.client.deleteVolume(self.sdUUID, self.spUUID, self.templateImgUUID, [self.templateVolUUID], True, False)
        )

    def forcedDeleteSharedVol(self):
        self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, self.templateVmUUID, self.imgUUID,
                self.volUUID1, self.templateImgUUID, self.templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL)
        )

        self.assertVdscOK(
            self.client.deleteVolume(self.sdUUID, self.spUUID, self.templateImgUUID, [self.templateVolUUID], True, True)
        )

class CreateVolumeWithInvalidSize(VolumeTestCaseBase):
    def test(self):
        self.imgUUID = vdsc.VDSClient.newUUID()
        self.volUUID = vdsc.VDSClient.newUUID()

        volsize = 0 #GB

        try:
            taskID = self.assertVdscOK(
                self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID, "Volly The Volume", blocked=False)
            )['uuid']
        except:
            return
        self.assertVdscTaskFail(self.client, taskID)

class ExtendVolume(VolumeTestCaseBase):
    def test(self):
        self.imgUUID = vdsc.VDSClient.newUUID()
        self.volUUID = vdsc.VDSClient.newUUID()

        volsize = 2048

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID, "Volly The Volume")
        )

        oldSize = int(self.assertVdscOK(
            self.client.getVolumeInfo(self.sdUUID, self.spUUID,
                self.imgUUID, self.volUUID))['info']['truesize'])

        self.assertVdscOK(
            self.client.extendVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID, str(oldSize + 2**30))
        )

        newSize = int(self.assertVdscOK(
            self.client.getVolumeInfo(self.sdUUID, self.spUUID,
                self.imgUUID, self.volUUID))['info']['truesize'])

        self.assertTrue(newSize > oldSize)

class MergeVolume(VolumeTestCaseBase):
    def setUp(self):
        self.agent = connectAgent(self.mycfg["VdsUri1"])

        VolumeTestCaseBase.setUp(self)

        self.vmUUID = vdsc.VDSClient.newUUID()
        self.imgUUID = vdsc.VDSClient.newUUID()
        self.baseVolUUID = vdsc.VDSClient.newUUID()
        self.imgUUID1 = vdsc.VDSClient.newUUID()
        self.volUUID1 = vdsc.VDSClient.newUUID()
        self.volUUID2 = vdsc.VDSClient.newUUID()
        self.volUUID3 = vdsc.VDSClient.newUUID()
        self.volsize = str(1024*(2**20)) #1 GB

    def _createBase(self, format, prealloc):
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            format, prealloc, "DATA", self.baseVolUUID, "Volly The Volume")
        )

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.baseVolUUID)
        )

        baseVolPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.imgUUID, self.baseVolUUID)
        )['path']

        self.agent.formatDiskImage(baseVolPath, [(10, "ext2")], format)

    def _mergeInternalVolume(self, format, prealloc):
        # Chain:   	    base -> snapshot_1 -> snapshot_2
        #                 ^       ^               ^
        # Snapshots:     sn1     sn2            leaf (invisible by VDC)
        self._createBase(format, prealloc)

        # Create snapshots
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Volly The Volume", self.imgUUID, self.baseVolUUID)
        )

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID2, "Volly The Volume", self.imgUUID, self.volUUID1)
        )
        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID2)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID2)
        )
        self.agent.addFileToDiskImage(volPath, 1, "/I.HATE.THIS", "Can you tell me where is my country lies?", vdsc.COW_FORMAT)

        # Delete sn2
        self.assertVdscOK(
            self.client.mergeSnapshots(self.sdUUID, self.spUUID, self.vmUUID, self.imgUUID,
            self.volUUID1, self.volUUID2)
        )

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID2)
        )
        self.assertTrue(self.agent.checkDiskImageSignature(volPath, vdsc.COW_FORMAT))

    def _mergeInternalVolumeFromTemplate(self, format, prealloc):
        # Chain:   	    base -> snapshot_1 -> snapshot_2
	 	#                 ^       ^               ^
        # Snapshots:     sn1     sn2            leaf (invisible by VDC)
        self._createBase(format, prealloc)

        # Create template
        templateVolUUID = vdsc.VDSClient.newUUID()
        templateImgUUID = vdsc.VDSClient.newUUID()
        templateVmUUID = vdsc.VDSClient.newUUID()

        self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, templateVmUUID, self.imgUUID,
                self.baseVolUUID, templateImgUUID, templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL)
        )
        # Create snapshots
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID1, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Volly The Volume", templateImgUUID, templateVolUUID)
        )

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID1, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID2, "Volly The Volume", self.imgUUID1, self.volUUID1)
        )
        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.imgUUID1, self.volUUID2)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID1, self.volUUID2)
        )
        self.agent.addFileToDiskImage(volPath, 1, "/I.HATE.THIS", "Can you tell me where is my country lies?", vdsc.COW_FORMAT)

        # Delete sn2
        self.assertVdscOK(
            self.client.mergeSnapshots(self.sdUUID, self.spUUID, self.vmUUID, self.imgUUID1,
            self.volUUID1, self.volUUID2)
        )

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID1, self.volUUID2)
        )
        self.assertTrue(self.agent.checkDiskImageSignature(volPath, vdsc.COW_FORMAT))

    def _mergeBaseVolume_1(self, format, prealloc):
        # Chain:   	    base -> snapshot_1
        #                 ^         ^
        # Snapshots:     sn1      leaf (invisible by VDC)
        self._createBase(format, prealloc)

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Volly The Volume", self.imgUUID, self.baseVolUUID)
        )

        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID1)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID1)
        )
        self.agent.addFileToDiskImage(volPath, 1, "/I.HATE.THIS", "Can you tell me where is my country lies?", vdsc.COW_FORMAT)

        # Delete sn1
        self.assertVdscOK(
            self.client.mergeSnapshots(self.sdUUID, self.spUUID, self.vmUUID, self.imgUUID,
            self.baseVolUUID, self.volUUID1)
        )

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID1)
        )
        self.assertTrue(self.agent.checkDiskImageSignature(volPath, format))

        # Create new snapshot
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID2, "Volly The Volume", self.imgUUID, self.volUUID1)
        )

        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID2)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID2)
        )
        self.assertTrue(self.agent.checkDiskImageSignature(volPath, vdsc.COW_FORMAT))

    def _mergeBaseVolume_2(self, format, prealloc):
        # Chain:   	    base -> snapshot_1 -> snapshot_2 -> snapshot_3
        #                 ^       ^               ^             ^
        # Snapshots:     sn1     sn2             sn3        leaf (invisible by VDC)
        self._createBase(format, prealloc)

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Volly The Volume", self.imgUUID, self.baseVolUUID)
        )

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID2, "Volly The Volume", self.imgUUID, self.volUUID1)
        )

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID3, "Volly The Volume", self.imgUUID, self.volUUID2)
        )
        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID3)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID3)
        )
        self.agent.addFileToDiskImage(volPath, 1, "/I.HATE.THIS", "Can you tell me where is my country lies?", vdsc.COW_FORMAT)

        # Delete sn1
        self.assertVdscOK(
            self.client.mergeSnapshots(self.sdUUID, self.spUUID, self.vmUUID, self.imgUUID,
            self.baseVolUUID, self.volUUID1)
        )

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volUUID3)
        )
        self.assertTrue(self.agent.checkDiskImageSignature(volPath, vdsc.COW_FORMAT))

    def testMergeInternal(self):
        self._mergeInternalVolume(format=vdsc.COW_FORMAT, prealloc=vdsc.SPARSE_VOL)

    def testMergeInternalFromTemplate(self):
        self._mergeInternalVolumeFromTemplate(format=vdsc.COW_FORMAT, prealloc=vdsc.SPARSE_VOL)

    def testMergeBase_1_SR(self):
        # Relevant for NFS only
        limitTestToConnectionType([eStorageType.nfs], self.mycfg["Connections"])
        self._mergeBaseVolume_1(format=vdsc.RAW_FORMAT, prealloc=vdsc.SPARSE_VOL)

    def testMergeBase_2_SR(self):
        # Relevant for NFS only
        limitTestToConnectionType([eStorageType.nfs], self.mycfg["Connections"])
        self._mergeBaseVolume_2(format=vdsc.RAW_FORMAT, prealloc=vdsc.SPARSE_VOL)

    def testMergeBase_1_SC(self):
        self._mergeBaseVolume_1(format=vdsc.COW_FORMAT, prealloc=vdsc.SPARSE_VOL)

    def testMergeBase_2_SC(self):
        self._mergeBaseVolume_2(format=vdsc.COW_FORMAT, prealloc=vdsc.SPARSE_VOL)

    def testMergeBase_1_PC(self):
        self._mergeBaseVolume_1(format=vdsc.COW_FORMAT, prealloc=vdsc.PREALLOCATED_VOL)

    def testMergeBase_2_PC(self):
        self._mergeBaseVolume_2(format=vdsc.COW_FORMAT, prealloc=vdsc.PREALLOCATED_VOL)

    def testMergeBase_1_PR(self):
        self._mergeBaseVolume_1(format=vdsc.RAW_FORMAT, prealloc=vdsc.PREALLOCATED_VOL)

    def testMergeBase_2_PR(self):
        self._mergeBaseVolume_2(format=vdsc.RAW_FORMAT, prealloc=vdsc.PREALLOCATED_VOL)


class ListVolumes(VolumeTestCaseBase):
    @classmethod
    def getConfigTemplate(cls):
        extraConfig = {
            "VolumesToCreate": {"default" : "3", "validator" : Validate.int},
        }

        extraConfig.update(__commonConfig__)

        return { cls.__name__ : extraConfig }

    def setUp(self):
        VolumeTestCaseBase.setUp(self)

        self.imgUUIDs = []
        self.volUUIDs = []
        for i in range(self.mycfg["VolumesToCreate"]):
            self.imgUUIDs.append(vdsc.VDSClient.newUUID())
            self.volUUIDs.append(vdsc.VDSClient.newUUID())

            volsize = 2048

            self.assertVdscOK(
                self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUIDs[i], volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUIDs[i], "Volly The Volume")
            )

    def test(self):
        resp = self.assertVdscOK(
                self.client.getVolumesList(self.sdUUID, self.spUUID)
            )

        uuidlist = resp['uuidlist']
        self.assertEquals(len(uuidlist), len(self.volUUIDs))

        for uuid in uuidlist:
            self.assertTrue(uuid in self.volUUIDs)

class CreateVolume(VolumeTestCaseBase):
    def test(self):
        self.imgUUID = vdsc.VDSClient.newUUID()
        self.volUUID = vdsc.VDSClient.newUUID()

        volsize = 5120

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID, "Volly The Volume")
        )

class SetVolumeLegality(VolumeTestCaseBase):
    def test(self):
        from pprint import pformat

        volUUID = vdsc.VDSClient.newUUID()
        imgUUID = vdsc.VDSClient.newUUID()
        vmUUID = vdsc.VDSClient.newUUID()

        volsize = 2048

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", volUUID, "Base volume")
        )

        self.assertVdscOK(
            self.client.setVolumeLegality(self.sdUUID, self.spUUID,
                imgUUID, volUUID, vdsc.ILLEGAL_VOL
            )
        )

        info = self.assertVdscOK(self.client.getVolumeInfo(self.sdUUID, self.spUUID,
                                                imgUUID, volUUID))['info']

        self.assertEquals(info['legality'], vdsc.ILLEGAL_VOL)

        self.assertVdscOK(
            self.client.setVolumeLegality(self.sdUUID, self.spUUID,
                imgUUID, volUUID, vdsc.LEGAL_VOL
            )
        )

        info = self.assertVdscOK(self.client.getVolumeInfo(self.sdUUID, self.spUUID,
                                                imgUUID, volUUID))['info']
        self.assertEquals(info['legality'], vdsc.LEGAL_VOL)

class DeleteImage(VolumeTestCaseBase):
    def setUp(self):
        VolumeTestCaseBase.setUp(self)

        self.volUUID1 = vdsc.VDSClient.newUUID()
        self.volUUID2 = vdsc.VDSClient.newUUID()
        self.volUUID3 = vdsc.VDSClient.newUUID()
        self.volUUID4 = vdsc.VDSClient.newUUID()
        self.imgUUID = vdsc.VDSClient.newUUID()
        self.vmUUID = vdsc.VDSClient.newUUID()
        self.templateVolUUID = vdsc.VDSClient.newUUID()
        self.templateImgUUID = vdsc.VDSClient.newUUID()
        self.templateVmUUID = vdsc.VDSClient.newUUID()

        self.volsize = 2048
        # create chain
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Base volume")
        )
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID2, "Snapshot 1 volume",
                self.imgUUID, self.volUUID1)
        )
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID3, "Snapshot 2 volume",
                self.imgUUID, self.volUUID2)
        )
        # create tree
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, self.volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID4, "Snapshot 3 volume",
                self.imgUUID, self.volUUID1)
        )

        self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, self.templateVmUUID, self.imgUUID,
                self.volUUID3, self.templateImgUUID, self.templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL)
        )


    def deleteImage(self,):
        self.assertVdscOK(
            self.client.deleteImage(self.sdUUID, self.spUUID, self.imgUUID, False, False)
        )

    def forceDeleteImage(self,):
        self.assertVdscOK(
            self.client.deleteImage(self.sdUUID, self.spUUID, self.imgUUID, False, True)
        )

    def templateImageDelete(self,):
        self.assertVdscOK(
            self.client.deleteImage(self.sdUUID, self.spUUID, self.templateImgUUID, True, False)
        )

    def templateImageWithChildrenDelete(self,):
        imgUUID2 = vdsc.VDSClient.newUUID()
        chUUID = vdsc.VDSClient.newUUID()
        # Create snapshot from the template
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, imgUUID2, self.volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", chUUID, "Snapshot from template",
                self.templateImgUUID, self.templateVolUUID)
        )
        self.assertVdscFail(
            self.client.deleteImage(self.sdUUID, self.spUUID, self.templateImgUUID, False, False)
        )

    def templateImageWithChildrenForceDelete(self,):
        imgUUID2 = vdsc.VDSClient.newUUID()
        chUUID = vdsc.VDSClient.newUUID()
        # Create snapshot from the template
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, imgUUID2, self.volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", chUUID, "Snapshot from template",
                self.templateImgUUID, self.templateVolUUID)
        )
        self.assertVdscOK(
            self.client.deleteImage(self.sdUUID, self.spUUID, self.templateImgUUID, False, True)
        )

class MoveImage(VolumeTestCaseBase):
    @classmethod
    def getConfigTemplate(cls):
        extraConfig = {
            "DomainClass2" : {"default" : "data", "validator" : eDomainClass.parse},
            "Domain2" : {"default" : "GUID, GUID", "validator" : Validate.list},
            "StorageType2": {"default" : "nfs", "validator" : eStorageType.parse},
        }

        extraConfig.update(__commonConfig__)

        return { cls.__name__ : extraConfig }

    def setUp(self):
        VolumeTestCaseBase.setUp(self)

        self.volUUID1 = vdsc.VDSClient.newUUID()
        self.volUUID2 = vdsc.VDSClient.newUUID()
        self.volUUID3 = vdsc.VDSClient.newUUID()
        self.imgUUID = vdsc.VDSClient.newUUID()
        self.vmUUID = vdsc.VDSClient.newUUID()


        self.domainTarget2 = generateDomainTargets(self.client, self.mycfg["Connections"], [self.mycfg["Domain2"]])[0]
        self.sdUUID2 = self.client.newUUID()
        #Create the tmp domain
        self.assertVdscOK(
            self.client.createStorageDomain(self.mycfg["StorageType2"], self.sdUUID2,
                "Storage Domain 2", self.domainTarget2, self.mycfg["DomainClass2"]
            )
        )

        self.assertVdscOK(
            self.client.attachStorageDomain(self.sdUUID2, self.spUUID)
            )

        self.assertVdscOK(
            self.client.activateStorageDomain(self.sdUUID2, self.spUUID)
        )

        volsize = 2048
        # create chain
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID2, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID1, "Base volume")
        )
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID2, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID2, "Snapshot 1 volume",
                self.imgUUID, self.volUUID1)
        )
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID2, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.volUUID3, "Snapshot 2 volume",
                self.imgUUID, self.volUUID2)
        )

    def copyOp(self,):
        self.assertVdscOK(
            self.client.moveImage(self.spUUID, self.sdUUID2, self.sdUUID, self.imgUUID,
                                   self.vmUUID, vdsc.COPYOP, False, False)
        )

    def moveOp(self,):
        self.assertVdscOK(
            self.client.moveImage(self.spUUID, self.sdUUID2, self.sdUUID, self.imgUUID,
                                   self.vmUUID, vdsc.MOVEOP, False, False)
        )

    def forcedMoveOp(self,):
        self.assertVdscOK(
            self.client.moveImage(self.spUUID, self.sdUUID2, self.sdUUID, self.imgUUID,
                                   self.vmUUID, vdsc.COPYOP, False, False)
        )
        self.assertVdscOK(
            self.client.moveImage(self.spUUID, self.sdUUID2, self.sdUUID, self.imgUUID,
                                   self.vmUUID, vdsc.MOVEOP, True, True)
        )


class CreateTemplate(VolumeTestCaseBase):
    def test(self):
        baseVolUUID = vdsc.VDSClient.newUUID()
        baseImgUUID = vdsc.VDSClient.newUUID()
        templateVolUUID = vdsc.VDSClient.newUUID()
        templateImgUUID = vdsc.VDSClient.newUUID()
        templateVmUUID = vdsc.VDSClient.newUUID()

        volsize = 2048

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, baseImgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", baseVolUUID, "Base volume")
        )

        self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, templateVmUUID, baseImgUUID,
                baseVolUUID, templateImgUUID, templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL)
        )

class CreateManySnapshotsFromTemplateSimultaneously(VolumeTestCaseBase):
    def test(self):
        baseVolUUID = vdsc.VDSClient.newUUID()
        baseImgUUID = vdsc.VDSClient.newUUID()
        templateVolUUID = vdsc.VDSClient.newUUID()
        templateImgUUID = vdsc.VDSClient.newUUID()
        templateVmUUID = vdsc.VDSClient.newUUID()

        volsize = 2048

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, baseImgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", baseVolUUID, "Base volume")
        )

        self.assertVdscOK(
            self.client.copyImage(self.sdUUID, self.spUUID, templateVmUUID, baseImgUUID,
                baseVolUUID, templateImgUUID, templateVolUUID, "Template of the beast", self.sdUUID,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.SPARSE_VOL)
        )

        tasks = []
        for i in range(10):
            tasks.append(self.assertVdscOK(
                self.client.createVolume(self.sdUUID, self.spUUID, baseImgUUID, volsize,
                    vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", vdsc.VDSClient.newUUID(), "Base volume", blocked=False)
            )['uuid'])

        for task in tasks:
            self.assertVdscTaskOK(self.client, task)

class CreateVolumeChain(VolumeTestCaseBase):
    @classmethod
    def getConfigTemplate(cls):
        extraConfig = {
            "ChainLength" : {"default" : 6, "validator" : Validate.int},
        }

        extraConfig.update(__commonConfig__)

        return { cls.__name__ : extraConfig }

    def test(self):
        chainLength = self.mycfg["ChainLength"]

        volsize = 5120

        volUUIDs = self.volUUIDs = [vdsc.VDSClient.newUUID() for i in range(chainLength)]
        self.imgUUID = vdsc.VDSClient.newUUID()

        self.createdVolumes = []

        for i in range(chainLength):
            #Get parent
            parentVol = BLANK_UUID
            if i > 0:
                parentVol = volUUIDs[i - 1]
            #Create volume
            self.assertVdscOK(
                self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", volUUIDs[i], "Vol no.%d" % i, srcImgUUID=self.imgUUID, srcVolUUID=parentVol)
            )

            self.createdVolumes.insert(0, volUUIDs[i])

            volType = self.assertVdscOK(
                self.client.getVolumeInfo(self.sdUUID, self.spUUID, self.imgUUID, self.volUUIDs[i]))['info']['voltype']

            #Make sure lineage is correct
            self.assertEqual(volType, eVolumeType.Leaf)
            for j in range(i - 1, -1, -1):
                volType = self.assertVdscOK(
                    self.client.getVolumeInfo(self.sdUUID, self.spUUID, self.imgUUID, self.volUUIDs[j]))['info']['voltype']

                self.assertEqual(volType, eVolumeType.Internal)

class CreateVolumeSun(VolumeTestCaseBase):
    @classmethod
    def getConfigTemplate(cls):
        extraConfig = {
            "RayLength" : {"default" : 6, "validator" : Validate.int},
            "NumOfRays" : {"default" : 6, "validator" : Validate.int},
        }

        extraConfig.update(__commonConfig__)

        return { cls.__name__ : extraConfig }

    def test(self):
        rayLength = self.mycfg["RayLength"]
        numOfRays = self.mycfg["NumOfRays"]

        volsize = 5120
        self.imgUUID = vdsc.VDSClient.newUUID()

        #Create root
        rootUUID = vdsc.VDSClient.newUUID()
        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", rootUUID, "Vol", srcImgUUID=self.imgUUID)
        )

        self.createdVolumes = [rootUUID]
        for i in range(numOfRays):
            parents = [rootUUID]
            for i in range(rayLength):
                #Create ray
                myUUID = vdsc.VDSClient.newUUID()

                self.assertVdscOK(
                    self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
                    vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", myUUID, "Vol no.%d" % i, srcImgUUID=self.imgUUID, srcVolUUID=parents[-1])
                )

                self.createdVolumes.insert(0, myUUID)

                volType = self.assertVdscOK(
                    self.client.getVolumeInfo(self.sdUUID, self.spUUID, self.imgUUID, myUUID))['info']['voltype']

                self.assertEqual(volType, eVolumeType.Leaf)

                #Make sure lineage is correct
                for p in parents:
                    volType = self.assertVdscOK(
                        self.client.getVolumeInfo(self.sdUUID, self.spUUID, self.imgUUID, p))['info']['voltype']

                    self.assertEqual(volType, eVolumeType.Internal)

                parents.append(myUUID)

class CreateVolumeTree(VolumeTestCaseBase):
    @classmethod
    def getConfigTemplate(cls):
        extraConfig = {
            "treeDepth" : {"default" : 4, "validator" : Validate.int},
            "treeBreadth" : {"default" : 2, "validator" : Validate.int},
        }

        extraConfig.update(__commonConfig__)

        return { cls.__name__ : extraConfig }

    def _calcTreeCord(self, itemNum, breadth):
        """
        Calculates the heredity of the Nth node.
        """
        #TODO : Make generator for performace benifits
        i = itemNum
        res = []
        while i >= breadth:
            i, ni = divmod(i, breadth)
            res.insert(0, ni)

        res.insert(0, i)

        return tuple(res)

    def test(self):
        treeDepth = self.mycfg["treeDepth"]
        treeBreadth = self.mycfg["treeBreadth"]
        volsize = 5120
        totalNumOfVols = (treeDepth ** treeBreadth) - 1
        self.imgUUID = vdsc.VDSClient.newUUID()

        #Create root
        rootUUID = vdsc.VDSClient.newUUID()
        sunUUIDs = [(rootUUID, [])]

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
            vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", rootUUID, "Vol", srcImgUUID=self.imgUUID)
        )

        #Start creating sun's rays
        self.createdVolumes = [rootUUID]
        for linkNum in range(totalNumOfVols):
            #Get father of link
            chain = self._calcTreeCord(linkNum, treeBreadth)
            parents = [rootUUID]
            parentUUID = rootUUID
            parentNode = sunUUIDs[0][1]
            for link in chain[:-1]:
                parentUUID = parentNode[link][0]
                parentNode = parentNode[link][1]
                parents.append(parentUUID)

            #Create volume
            myUUID = vdsc.VDSClient.newUUID()

            self.assertVdscOK(
                self.client.createVolume(self.sdUUID, self.spUUID, self.imgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", myUUID, "Vol", srcImgUUID=self.imgUUID, srcVolUUID=parentUUID)
            )

            #Add to data structures
            self.createdVolumes.insert(0, myUUID)
            parentNode.append((myUUID, []))

            #Validate that I'm a leaf
            volType = self.assertVdscOK(
                self.client.getVolumeInfo(self.sdUUID, self.spUUID, self.imgUUID, myUUID))['info']['voltype']

            self.assertEqual(volType, eVolumeType.Leaf)

            #Validate that the lineage is typed correctly
            for parent in parents:
                volType = self.assertVdscOK(
                    self.client.getVolumeInfo(self.sdUUID, self.spUUID, self.imgUUID, parent))['info']['voltype']

                self.assertEqual(volType, eVolumeType.Internal)

class RecoveringFromMissingLink(VolumeTestCaseBase):
    def setUp(self):
        limitTestToConnectionType([eStorageType.iscsi, eStorageType.fcp], self.mycfg["Connections"])
        self.agent = connectAgent(self.mycfg["VdsUri1"])

        VolumeTestCaseBase.setUp(self)

        self.VolUUID = vdsc.VDSClient.newUUID()
        self.ImgUUID = vdsc.VDSClient.newUUID()

        volsize = str(100 * (2 ** 20))

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID, self.spUUID, self.ImgUUID,
                volsize, vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA",
                self.VolUUID, "Missing link lab rat")
        )

        # now activate the LV
        self.agent.activateLV(self.sdUUID, self.VolUUID)
        # and remove its /dev link
        path = os.path.join("/dev", self.sdUUID, self.VolUUID)
        self.agent.removeFile(path)


    def test(self):

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID, self.spUUID,
                self.ImgUUID, self.VolUUID)
        )


def suite():
    tests = {
        CreateVolume : ["test"],
        DeleteVolume : ["deleteVol", "forcedDeleteVol",
                         "deleteSharedVol", "forcedDeleteSharedVol",
                         "deleteVolWithChildren", "forcedDeleteVolWithChildren"],
        CreateVolumeChain : ["test"],
        CreateVolumeTree : ["test"],
        SetVolumeDescription : ["test"],
        CreateVolumeWithInvalidSize : ["test"],
        CreateVolumeSun : ["test"],
        CreateTemplate : ["test"],
        MoveImage : ["copyOp", "moveOp", "forcedMoveOp"],
        SetVolumeLegality : ["test"],
        NewVolumeInfo : ["test"],
        MergeVolume : ["testMergeInternal", "testMergeInternalFromTemplate",
                        "testMergeBase_1_SR", "testMergeBase_2_SR",
                        "testMergeBase_1_SC", "testMergeBase_2_SC",
                        "testMergeBase_1_PC", "testMergeBase_2_PC",
                        "testMergeBase_1_PR", "testMergeBase_2_PR"],
        ListVolumes : ["test"],
        ExtendVolume : ["test"],
        RefCountTest : ["test"],
        RecoveringFromMissingLink : ["test"],
        DeleteImage : ["deleteImage", "forceDeleteImage", "templateImageDelete",
                        "templateImageWithChildrenDelete", "templateImageWithChildrenForceDelete"],
        CreateManySnapshotsFromTemplateSimultaneously : ['test']
    }

    resSuite = ut.TestSuite()
    for testcase, methods in tests.iteritems():
        resSuite.addTests(map(testcase, methods))

    return resSuite

validateConfig = lambda cfg : vdst.validateSuiteConfig(suite(), cfg)
